using System;

namespace EventReactor
{
    public abstract class AsyncEvent : IAsyncEvent
    {
        private Action _end;
        public void EndCallback()
        {
            _end();
        }
        public EndMark Call => EndMark.Call;
        public EndMark End => EndMark.End;
        Action IAsyncEvent.EndAct
        {
            get => _end;
            set => _end = value;
        }
    }
    public abstract class RequestBase<TResult>: AsyncEvent,IRequest, IRequest<TResult> where TResult:IResult,new()
    {
        protected TResult _result;
        public TResult ResultValue => _result;
        public RequestBase()
        {
            _result = new TResult();
        }
        public bool TryGet(out TResult result)
        {
            result = _result;
            return result == null;
        }
        public EndMark SetSuccessAndMark(bool success,EndMark mark)
        {
            _result.IsSuccess = success;
            return mark;
        }
        public EndMark EndSucceed => SetSuccessAndMark(true, EndMark.End);
        public EndMark EndFail => SetSuccessAndMark(false, EndMark.End);
        public EndMark CallSucceed => SetSuccessAndMark(true, EndMark.Call);
        public EndMark CallFail => SetSuccessAndMark(false, EndMark.Call);
        IResult IRequest.Result => _result;
        TResult IRequest<TResult>.Result => _result;
        IRequest IRequest<TResult>.AsIRequest => this;

    }
    public abstract class OrderedRequest<TResult> : RequestBase<TResult>, IOrderedRequest,IOrderedRequest<TResult> where TResult:IResult,new()
    {
        protected bool _isReadOnly;
        private object _readOnlyMarker;
        public bool IsReadOnly => _isReadOnly;
        public object ReadOnlyMarker => _readOnlyMarker;
        public bool TrySet(TResult result)
        {
            if (IsReadOnly) return false;
            _result = result;
            return true;
        }
        public bool TrySetSuccess(bool isSuccess)
        {
            if (IsReadOnly) return false;
            _result.IsSuccess = isSuccess;
            return true;
        }
        /// <summary>
        /// 尝试设置请求结果并设为只读
        /// </summary>
        public bool TrySetReadOnly(TResult result, object readOnlyMarker)
        {
            TrySet(result);
            MarkReadOnly(readOnlyMarker);
            return true;
        }
        public void MarkReadOnly(object sender)
        {
            if (_isReadOnly) return;
            _isReadOnly = true;
            _readOnlyMarker = sender;
        }
        IResult IRequest.Result => _result;
        IOrderedRequest IOrderedRequest<TResult>.AsIOrderedRequest => this;
    }
    public abstract class WhenAllRequest<TResult> : RequestBase<TResult>, IWhenAllRequest, IWhenAllRequest<TResult> where TResult : IResult, new()
    {
        IWhenAllRequest IWhenAllRequest<TResult>.AsIWhenAllRequest => this;
    }
    public abstract class Request<TResult> : OrderedRequest<TResult>, IWhenAllRequest, IWhenAllRequest<TResult> where TResult : IResult, new()
    {
        IWhenAllRequest IWhenAllRequest<TResult>.AsIWhenAllRequest => this;
    }
    /// <summary>
    /// 如果你希望Result可以被部分修改，使用此类。反之，请使用结构体。
    /// </summary>
    public abstract class Result : IResult
    {
        public bool isSuccess;
        public bool IsSuccess
        {
            get => isSuccess;
            set => isSuccess = value;
        }
    }
    /// <summary>
    /// 如果你希望Result可以被部分修改，使用此类。反之，请使用结构体。
    /// </summary>
    public abstract class Result<T> : Result, IResult<T>
    {
        private T _mainValue;
        IResult IResult<T>.AsIResult => this;
        public T MainValue
        {
            get => _mainValue;
            set => _mainValue = value;
        }
    }
    public abstract class Query : IQuery 
    {
        protected bool _isReadOnly;
        private object _readOnlyMarker;
        public bool IsReadOnly => _isReadOnly;
        public object ReadOnlyMarker => _readOnlyMarker;
        public void MarkReadOnly(object sender)
        {
            if (_isReadOnly) return;
            _isReadOnly = true;
            _readOnlyMarker = sender;
        }
    }
    public abstract class Query<T> : Query, IQuery<T>
    {
        private T _mainValue;
        IQuery IQuery<T>.AsIQuery => this;
        public T MainValue
        {
            get => _mainValue;
            set
            {
                if (!_isReadOnly)
                    _mainValue = value;
            }
        }
    }
    public abstract class Query<TSelf,TValue> : Query<TValue> where TSelf : Query<TSelf, TValue>,new()
    {
        public static TValue V(object sender, ICanQuery view)
        {
            var query = new TSelf();
            query.Value(sender, view);
            return query.MainValue;
        }
    }
}
